package org.neowei.image.api.impl;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.neowei.common.NioFileHelper;
import org.neowei.common.exception.NativeException;
import org.neowei.image.api.ImageApi;
import org.neowei.image.api.ImageOption;
import org.neowei.image.filtering.handle.BGResizeHandle;
import org.neowei.image.filtering.handle.CropHandle;
import org.neowei.image.filtering.handle.CropResizeHandle;
import org.neowei.image.filtering.handle.IHandle;
import org.neowei.image.filtering.handle.ResizeHandle;
import org.neowei.image.filtering.handle.WaterHandle;

public class ImageApiImpl implements ImageApi {
	private ResizeHandle resizeHandle = null;
	private BGResizeHandle bGResizeHandle = null;
	private CropHandle cropHandle = null;
	private WaterHandle waterHandle = null;
	private CropResizeHandle cropResizeHandle = null;
	public final long createtime;

	public ImageApiImpl() {
		createtime = System.nanoTime();
	}

	@Override
	public byte[] doResizeImage(ImageOption imageOption) throws Exception {
		return this.getFinalBytes(imageOption, this.getResizeHandle());
	}

	@Override
	public byte[] doBGResizeImage(ImageOption imageOption) throws Exception {
		return this.getFinalBytes(imageOption, this.getbGResizeHandle());
	}

	@Override
	public byte[] doCropImage(ImageOption imageOption) throws Exception {
		return this.getFinalBytes(imageOption, this.getCropHandle());
	}

	@Override
	public byte[] doWaterImage(ImageOption imageOption) throws Exception {
		return this.getFinalBytes(imageOption, this.getWaterHandle());
	}

	@Override
	public byte[] doCropResizeImage(ImageOption imageOption) throws Exception {
		return this.getFinalBytes(imageOption, this.getCropResizeHandle());
	}

	@Override
	public int compareTo(ImageApiImpl o) {
		return (int) (o.createtime - this.createtime);
	}

	final private byte[] getFinalBytes(ImageOption imageOption, IHandle iHandle) throws Exception {
		String despathWithFilename = imageOption.getDespathWithFilename();
		File file = new File(despathWithFilename);
		if (file.exists()) {
			return NioFileHelper.getByte(file);
		}
		BufferedImage outimage = iHandle.getBufferedImage(imageOption, this.getSrcBufferedImage(imageOption));
		if (imageOption.isIsdelete()) {
			return this.getBytes(outimage);
		} else {
			ImageIO.write(outimage, "jpg", file);
			return this.getBytes(outimage);
		}
	}

	final private byte[] getBytes(BufferedImage outimage) {
		ByteArrayOutputStream outstream = new ByteArrayOutputStream();
		try {
			ImageIO.write(outimage, "jpeg", outstream);
		} catch (IOException e) {
			throw new NativeException("can't write outstream please check despath", e);
		}
		return outstream.toByteArray();
	}

	private BufferedImage getSrcBufferedImage(ImageOption imageOption) {
		BufferedImage srcImage = null;
		File srcfile = new File(imageOption.getSrcpathWithFilename());
		try {
			srcImage = ImageIO.read(srcfile);
			imageOption.setSrcwidth(srcImage.getWidth());
			imageOption.setSrcheight(srcImage.getHeight());
		} catch (IOException e) {
			throw new NativeException("can't read srcfile please check picfilename and srcpath", e);
		}
		return srcImage;
	}

	private ResizeHandle getResizeHandle() {
		return this.resizeHandle == null ? this.resizeHandle = new ResizeHandle() : this.resizeHandle;
	}

	private BGResizeHandle getbGResizeHandle() {
		return this.bGResizeHandle == null ? this.bGResizeHandle = new BGResizeHandle() : this.bGResizeHandle;
	}

	private CropHandle getCropHandle() {
		return this.cropHandle == null ? this.cropHandle = new CropHandle() : this.cropHandle;
	}

	private WaterHandle getWaterHandle() {
		return this.waterHandle == null ? this.waterHandle = new WaterHandle() : this.waterHandle;
	}

	private CropResizeHandle getCropResizeHandle() {
		return this.cropResizeHandle == null ? this.cropResizeHandle = new CropResizeHandle() : this.cropResizeHandle;
	}

}
